<?php

namespace app\privatearea\controller\mall\v1;

use app\common\cachemodel\privatearea\PrivateAreaMallCompany;
use app\common\cachemodel\privatearea\PrivateAreaMallGoods;
use app\common\cachemodel\privatearea\PrivateAreaMallGoodsAttr;
use app\common\cachemodel\privatearea\PrivateAreaOrders;
use app\common\cachemodel\privatearea\PrivateAreaUserAddress;
use app\common\lib\PushQueue;
use app\common\lib\Util;
use app\privatearea\controller\MallAuth;
use app\privatearea\service\PriOrderLib;
use think\Db;
use think\Log;

class Order extends MallAuth
{
    //  订单未支付关闭等待时间
    public $orderPayCloseDelayTime = 300;

    /**
     * 下单
     * @return \think\response\Json
     */
    public function orderPay()
    {
        $sid = input('sid/d', 0);
        $tradeType = input('trade_type/d', 0);
        $addressId = input('address_id/d', 0);
        $remark = trim(input('remark/s', ''));
        $isCheck = input('is_check/d', 0);
        $hash = input('hash/s', '');
        $callbackUrl = input('callback_url/s', '');
        $openid = input('openid/s', '');
        $code = input('code/s', '');

        if (Util::commentCheck($this->user['id'], [
            'action' => 'orderPay',
            'sid' => $sid,
            'trade_type' => $tradeType,
            'address_id' => $addressId,
            'remark' => $remark,
            'is_check' => $isCheck,
            'hash' => $hash,
            'callback_url' => $callbackUrl,
            'openid' => $openid,
            'code' => $code,
        ], 3))
        {
            return show(config('code.error'), '请求频繁，请稍后再试～');
        }

        if (!in_array($tradeType, [1, 2, 3], true))
        {
            return show(config('code.error'), '服务异常，支付类型错误～');
        }
        if (!$sid)
        {
            return show(config('code.error'), '服务异常，商品信息错误～');
        }
        if (!$addressId)
        {
            return show(config('code.error'), '下单失败，请选择收货地址～');
        }
        if (mb_strlen($remark) > 30)
        {
            return show(config('code.error'), '下单失败，备注信息不能超过30个字符～');
        }
        if (!in_array($isCheck, [0, 1], true))
        {
            return show(config('code.error'), '请求异常，请稍后再试～');
        }
        $remark = htmlspecialchars($remark);
        $privateAreaMallGoodsModel = new PrivateAreaMallGoods();
        $privateAreaMallGoodsAttrModel = new PrivateAreaMallGoodsAttr();
        $goodAttrDetail = $privateAreaMallGoodsAttrModel->getInfoById($sid);
        if (!$goodAttrDetail)
        {
            return show(config('code.error'), '服务异常，商品信息错误～');
        }
        if ($goodAttrDetail['status'] !== 1)
        {
            return show(config('code.error'), '下单失败，商品已下架～');
        }
        if ($goodAttrDetail['inventory'] < 1)
        {
            return show(config('code.error'), '下单失败，商品库存不足～');
        }
        // redis缓存 扣除库存
        $resInventory = $privateAreaMallGoodsAttrModel->goodInventoryChangeCache($sid, -1);
        if ($resInventory < 0)
        {   // 还原 缓存
            $privateAreaMallGoodsAttrModel->goodInventoryChangeCache($sid, 1);
            return show(config('code.error'), '下单失败，商品库存不足～');
        }
        $goodDetail = $privateAreaMallGoodsModel->getInfoById($goodAttrDetail['gid']);
        if (!$goodDetail)
        {
            return show(config('code.error'), '服务异常，商品信息错误～');
        }
        if ($goodDetail['status'] !== 1)
        {
            return show(config('code.error'), '下单失败，商品已下架～');
        }
        if (!$goodDetail['has_quality_check'])
        {
            $isCheck = 2;   // 商品不支持 三方质检
        }
        // 获取公司信息
        $privateAreaMallCompanyModel = new PrivateAreaMallCompany();
        $companyData = $privateAreaMallCompanyModel->getInfoById($goodDetail['cid']);
        if (!$companyData)
        {
            return show(config('code.error'), '服务异常，商品信息错误～');
        }
        if (($tradeType === 1 && !in_array(1, $companyData['pay_type'])) || (in_array($tradeType, [2, 3], true) && !in_array(2, $companyData['pay_type'])))
        {
            return show(config('code.error'), '服务异常，商品信息错误～');
        }
        $addressData = (new PrivateAreaUserAddress())->getInfoById($addressId);
        if (!$addressData || $addressData['uid'] !== $this->user['id'])
        {
            return show(config('code.error'), '下单失败，收货地址不存在～');
        }
        if (mb_strlen($hash) > 30)
        {
            return show(config('code.error'), '请求异常，请稍后再试～');
        }
        if (Util::commentCheck($this->user['id'], ['action' => 'orderPay', 'sid' => $sid, 'trade_type' => $tradeType, 'address_id' => $addressId, 'is_check' => $isCheck, 'hash' => $hash, 'callback_url' => $callbackUrl, 'openid' => $openid, 'code' => $code], 3))
        {
            return show(config('code.error'), '操作频繁，请稍后再试～');
        }
        $type = 57;
        try
        {
            Db::startTrans();
            $extend = [
                'mall' => [
                    'is_check' => $isCheck,
                    'remark' => $remark,
                    'gid' => $goodAttrDetail['gid'],
                    'aid' => $addressId,
                    'cid' => $goodDetail['cid'],
                ],
                'kd' => [
                    'id' => '',
                    'company' => '',
                    'send_time' => '',
                    'address' => sprintf('%s %s %s %s', $addressData['country'], $addressData['province'], $addressData['city'], $addressData['address_desc']),
                    'phone' => $addressData['phone'],
                    'name' => $addressData['name'],
                ],
            ];
            $orderData = [
                'status' => 1,
                'good_type' => 7,
                'hash' => $hash,
                'uid' => $this->user['id'],
                'order_id' => str_pad($type, 2, '0', STR_PAD_LEFT) . date('YmdHis') . str_pad(random_int(1, 9999), 4, '0', STR_PAD_LEFT),
                'qid' => $sid,
                'trade_type' => $tradeType,
                'total_amount' => $goodAttrDetail['now_price'],
                'create_time' => $this->request->time(),
                'extend' => json_encode($extend, JSON_UNESCAPED_UNICODE),
                'pay_time' => 0,
                'success_time' => 0,
                'channel' => 0,
            ];
            $oid = (new PrivateAreaOrders())->insertDataGetId($orderData);
            if (!$oid)
            {
                Db::rollback();
                return show(config('code.error'), '下单失败，请稍后再试～');
            }
            // 数据库 扣除库存
            $privateAreaMallGoodsAttrModel->UpdateDataByDb($sid, ['inventory' => Db::raw('inventory -1')]);

            Db::commit();
        }
        catch (\Exception $e)
        {
            \think\Log::write(__CLASS__ . ' => ' . __FUNCTION__ . '()异常：' . $e->getMessage() . '失败信息：' . $e->getFile() . ':' . $e->getLine(), 'error', true);
            Db::rollback();
        }
        // 5 分钟
        PushQueue::CloseOrder($orderData['order_id'], $this->orderPayCloseDelayTime);
        if (3 === $tradeType)
        {//如果是微信支付，那么如果存在openid，那么为微信js支付
            // 微信JSAPI支付
            if (empty($openid))
            {   // 如果openid没有，那么通过传过来的code获取access_token，然后再获取openid
                if (!empty($code))
                {   // 去换取用户openid
                    $wechatConfig = $privateAreaMallCompanyModel->getCompanyPayConfig($companyData, $tradeType);
                    $wxInfo = $this->wechatGetAccessTokenAndOpenidByCode($wechatConfig, $code);
                    if (!$wxInfo || isset($wxInfo['errcode']))
                    {
                        Log::write("获取Access_token错误：" . json_encode($wxInfo), 'error');
                        return show(config('code.error'), $wxInfo['errmsg']);
                    }
                    $openid = $wxInfo['openid'] ?? '';
                } else
                { // 异常抛出
                    return show(config('code.error'), 'code不能为空！');
                }
            }
        }
        //支付订单
        $arr = PriOrderLib::unifyPayOrder([
            'trade_type' => $tradeType,
            'total_amount' => $goodAttrDetail['now_price'],
            'pay_des' => $goodDetail['name'],
            'order_id' => $orderData['order_id'], // 订单编号
            'openid' => $openid,
            'callback_url' => $callbackUrl,
        ], $privateAreaMallCompanyModel->getCompanyPayConfig($companyData, $tradeType));

        if ($arr['status'])
        {
            $arr['data']['openid'] = $openid;
            return show(config('code.success'), '请求成功', $arr['data']);
        } else
        {
            Log::write('私域H5 实物商品订单 下单 调取支付数据失败【OrdersLib::unifyPayOrder】：' . json_encode($arr, JSON_UNESCAPED_UNICODE), 'error');
            return show(config('code.error'), '服务异常，下单失败～');
        }
    }

    /**
     * 继续支付
     * @return \think\response\Json
     * @throws \Exception
     */
    public function payAgain()
    {
        $orderId = input('order_id/s', '');
        $tradeType = input('trade_type/d', 0);
        $addressId = input('address_id/d', 0);
        $remark = trim(input('remark/s', ''));
        $isCheck = input('is_check/d', 0);
        $callbackUrl = input('callback_url/s', '');
        $openid = input('openid/s', '');
        $code = input('code/s', '');
        if (!in_array($tradeType, [1, 2, 3], true))
        {
            return show(config('code.error'), '服务异常，支付类型错误～');
        }
        if (empty($orderId))
        {
            return show(config('code.error'), '服务异常，订单信息错误～');
        }
        if (!$addressId)
        {
            return show(config('code.error'), '下单失败，请选择收货地址～');
        }
        if (mb_strlen($remark) > 30)
        {
            return show(config('code.error'), '下单失败，备注信息不能超过30个字符～');
        }
        if (!in_array($isCheck, [0, 1], true))
        {
            return show(config('code.error'), '请求异常，请稍后再试～');
        }
        $remark = htmlspecialchars($remark);
        $privateAreaOrderModel = new PrivateAreaOrders();
        $orderInfo = $privateAreaOrderModel->getInfoById($orderId);
        if (!$orderInfo || $this->user['id'] !== $orderInfo['uid'])
        {
            return show(config('code.error'), '服务异常，订单信息错误～');
        }
        if ($orderInfo['status'] === 3)
        {
            return show(config('code.error'), '订单已关闭，请重新下单～');
        }
        if ($orderInfo['status'] !== 1)
        {
            return show(config('code.error'), '服务异常，订单状态错误～');
        }
        $extend = $orderInfo['extend'] ? json_decode($orderInfo['extend'], true) : [];
        $addressData = (new PrivateAreaUserAddress())->getInfoById($addressId);
        if (!$addressData || $addressData['uid'] !== $this->user['id'])
        {
            return show(config('code.error'), '下单失败，收货地址不存在～');
        }
        $privateAreaMallGoodsModel = new PrivateAreaMallGoods();
        $goodDetail = $privateAreaMallGoodsModel->getInfoById($extend['mall']['gid'], ['name', 'has_quality_check']);
        if (!$goodDetail['has_quality_check'])
        {
            $isCheck = 2;   // 商品不支持 三方质检
        }
        $extend['mall']['is_check'] = $isCheck;
        $extend['mall']['remark'] = $remark;
        $extend['mall']['aid'] = $addressId;
        $extend['kd']['address'] = sprintf('%s %s %s %s', $addressData['country'], $addressData['province'], $addressData['city'], $addressData['address_desc']);
        $extend['kd']['phone'] = $addressData['phone'];
        $extend['kd']['name'] = $addressData['name'];
        //  更新订单信息
        (new PrivateAreaOrders())->updateOrderInfo($orderId, ['trade_type' => $tradeType, 'extend' => json_encode($extend, JSON_UNESCAPED_UNICODE)]);
        // 获取公司信息
        $privateAreaMallCompanyModel = new PrivateAreaMallCompany();
        $companyData = $privateAreaMallCompanyModel->getInfoById($extend['mall']['cid']);
        if (3 === $tradeType)
        {//如果是微信支付，那么如果存在openid，那么为微信js支付
            // 微信JSAPI支付
            if (empty($openid))
            {   // 如果openid没有，那么通过传过来的code获取access_token，然后再获取openid
                if (!empty($code))
                {   // 去换取用户openid
                    $wechatConfig = $privateAreaMallCompanyModel->getCompanyPayConfig($companyData, $tradeType);
                    $wxInfo = $this->wechatGetAccessTokenAndOpenidByCode($wechatConfig, $code);
                    if (!$wxInfo || isset($wxInfo['errcode']))
                    {
                        Log::write("获取Access_token错误：" . json_encode($wxInfo), 'error');
                        return show(config('code.error'), $wxInfo['errmsg']);
                    }
                    $openid = $wxInfo['openid'] ?? '';
                } else
                { // 异常抛出
                    return show(config('code.error'), 'code不能为空！');
                }
            }
        }
        //支付订单
        $arr = PriOrderLib::unifyPayOrder([
            'trade_type' => $tradeType,
            'total_amount' => $orderInfo['total_amount'],
            'pay_des' => $goodDetail['name'],
            'order_id' => $orderId, // 订单编号
            'openid' => $openid,
            'callback_url' => $callbackUrl,
        ], $privateAreaMallCompanyModel->getCompanyPayConfig($companyData, $tradeType));

        if ($arr['status'])
        {
            $arr['data']['openid'] = $openid;
            return show(config('code.success'), '请求成功', $arr['data']);
        } else
        {
            Log::write('私域H5 实物商品订单 下单 调取支付数据失败【OrdersLib::unifyPayOrder】：' . json_encode($arr, JSON_UNESCAPED_UNICODE), 'error');
            return show(config('code.error'), '服务异常，请稍后再试～');
        }
    }

    /**
     * 订单列表
     */
    public function orderList()
    {
        $page = input('page/d', 1);

        $page = $page < 1 ? 1 : $page;

        $data = (new PrivateAreaOrders())->getOrderList2($this->user['id'], $page);

        return show(config('code.success'), '请求成功', $data);
    }

    /**
     * 订单详情
     */
    public function orderDetail()
    {
        $orderId = input('order_id/s', '');
        if (!$orderId)
        {
            return show(config('code.error'), '请求异常，请稍后再试～');
        }
        $privateAreaOrdersModel = new PrivateAreaOrders();
        $orderInfo = $privateAreaOrdersModel->getInfoById($orderId);
        if (!$orderInfo || $orderInfo['uid'] !== $this->user['id'])
        {
            return show(config('code.error'), '服务异常，订单不存在～');
        }
        if ($orderInfo['status'] === 1 && $this->request->time() - $orderInfo['create_time'] > $this->orderPayCloseDelayTime + 30)
        {   // 待支付 并且 过了可支付时间 并且还没有关闭订单  进行关闭订单处理
            $orderInfo['status'] = 3;
            $orderInfo['success_time'] = $this->request->time();
            $privateAreaOrdersModel->updateOrderInfo($orderId, ['status' => 3, 'success_time' => $orderInfo['success_time']]);
        }
        $extend = $orderInfo['extend'] ? json_decode($orderInfo['extend'], true) : [];
        if ($orderInfo['status'] === 6 && $this->request->time() - $extend['kd']['send_time'] > 864000)
        {   // 已发货 等待收货 发货后 10天自动完成订单
            $orderInfo['status'] = 4;
            $orderInfo['success_time'] = $extend['kd']['send_time'] + 864000;
            $privateAreaOrdersModel->updateOrderInfo($orderId, ['status' => 4, 'success_time' => $orderInfo['success_time']]);
        }
        $progressData = null;
        if ($orderInfo['status'] !== 3)
        {   // 1=>待支付 2=>待解答|待发货  3=>未支付订单关闭 4=>已完成 5=>已退款 6=>待收货
            $kdId = $extend['kd']['id'] ?? '';
            switch ($orderInfo['status'])
            {
                case 1:
                    $progress = 0;
                    $statusDesc = '待支付';
                    break;
                case 2:
                    $progress = 0;
                    $statusDesc = '待发货';
                    break;
                case 4:
                    $progress = 100;
                    $statusDesc = sprintf("已收货  运单号:%s", $kdId);
                    break;
                case 5: // 已退款
                    $progress = $kdId ? 100 : 0;
                    $statusDesc = $kdId ? sprintf("已退款  运单号:%s", $kdId) : '已退款';
                    break;
                case 6:
                    $progress = 50;
                    $statusDesc = sprintf("已发货，10天后自动签收  运单号:%s", $kdId);
                    break;
                default:
                    $progress = 0;
                    $statusDesc = '';
            }
            $progressData = [
                'progress' => $progress,
                'status_desc' => $statusDesc,
                'copy_text' => $kdId,
            ];
        }
        $privateAreaMallGoodsModel = new PrivateAreaMallGoods();
        $privateAreaMallGoodsAttrModel = new PrivateAreaMallGoodsAttr();
        $goodAttrData = $privateAreaMallGoodsAttrModel->getInfoById($orderInfo['qid']);
        $goodData = $privateAreaMallGoodsModel->getInfoById($goodAttrData['gid']);
        $addressData = [
            'id' => $extend['mall']['aid'],
            'phone' => $extend['kd']['phone'],
            'name' => $extend['kd']['name'],
            'address' => $extend['kd']['address'],
        ];
        $payModeList = [];
        if ($orderInfo['status'] === 1)
        {
            $privateAreaMallCompanyModel = new PrivateAreaMallCompany();
            $companyData = $privateAreaMallCompanyModel->getInfoById($extend['mall']['cid']);
            if ($this->isWexinBrowser() && in_array(2, $companyData['pay_type']))
            {
                $payModeList = [
                    [       // 3 => 微信JSAPI支付
                        'trade_type' => 3,
                        'name' => '微信支付',
                        'icon' => '/test/trade_type/trade_type2.png',
                        'is_selected' => 1,
                    ],
                ];
                $payModeList[] = [    // 1=>支付宝H5支付
                    'trade_type' => 1,
                    'name' => '支付宝支付',
                    'icon' => '/test/trade_type/trade_type1.png',
                    'is_selected' => 0,
                ];
            } else
            {
                if (in_array(2, $companyData['pay_type']))
                {
                    $payModeList[] = [ // 2 => 微信H5支付
                        'trade_type' => 2,
                        'name' => '微信支付',
                        'icon' => '/test/trade_type/trade_type2.png',
                        'is_selected' => 1,
                    ];
                }
                if (in_array(1, $companyData['pay_type']))
                {
                    $payModeList[] = [    // 1=>支付宝H5支付
                        'trade_type' => 1,
                        'name' => '支付宝支付',
                        'icon' => '/test/trade_type/trade_type1.png',
                        'is_selected' => 0,
                    ];
                }
            }
        }
        $detailList = [
            [
                'name' => '金额',
                'value' => (float)$orderInfo['total_amount'],
                'type' => 1,
                'key' => '',
                'is_selected' => 0,
            ], [
                'name' => '运费',
                'value' => '包邮',
                'type' => 0,
                'key' => '',
                'is_selected' => 0,
            ],
        ];
        if ($orderInfo['status'] === 1)
        {
            if ($goodData['has_quality_check'])
            {   // 支持 三方质检
                $detailList[] = [
                    'name' => '质检',
                    'value' => '三方质检',
                    'type' => 3,
                    'key' => 'is_check',
                    'is_selected' => $extend['mall']['is_check'] ?? 0,
                ];
            }
            $detailList[] = [
                'name' => '备注',
                'value' => $extend['mall']['remark'] ?? '',
                'type' => 4,
                'key' => 'remark',
                'is_selected' => 0,
            ];
        } else
        {
            if ($goodData['has_quality_check'])
            {   // 支持 三方质检
                $detailList[] = [
                    'name' => '质检',
                    'value' => $extend['mall']['is_check'] ? '走三方质检' : '不走三方质检',
                    'type' => 0,
                    'key' => '',
                    'is_selected' => '',
                ];
            }
            $detailList[] = [
                'name' => '备注',
                'value' => $extend['mall']['remark'] ?? '',
                'type' => 0,
                'key' => '',
                'is_selected' => 0,
            ];
        }
        if (!in_array($orderInfo['status'], [1, 3], true))
        {
            $detailList[] = [
                'name' => '支付方式',
                'value' => $orderInfo['trade_type'] == 1 ? '支付宝支付' : '微信支付',
                'type' => 0,
                'key' => '',
                'is_selected' => 0,
            ];
        }
        $detailList[] = [
            'name' => '下单时间',
            'value' => date('Y-m-d H:i', $orderInfo['create_time']),
            'type' => 0,
            'key' => '',
            'is_selected' => 0,
        ];
        if (in_array($orderInfo['status'], [2, 4, 5, 6], true))
        {   // 1=>待支付 2=>待解答|待发货  3=>未支付订单关闭 4=>已完成 5=>已退款 6=>待收货
            $detailList[] = [
                'name' => '支付时间',
                'value' => date('Y-m-d H:i', $orderInfo['pay_time']),
                'type' => 0,
                'key' => '',
                'is_selected' => 0,
            ];
        }
        $detailList[] = [
            'name' => '订单号',
            'value' => $orderId,
            'type' => 2,
            'key' => '',
            'is_selected' => 0,
        ];
        if ($orderInfo['status'] === 5)
        {   // 已退款
            $detailList[] = [
                'name' => '退款时间',
                'value' => date('Y-m-d H:i', $orderInfo['return_time']),
                'type' => 0,
                'key' => '',
                'is_selected' => 0,
            ];
            $detailList[] = [
                'name' => '退款金额',
                'value' => sprintf("%s元", $orderInfo['return_amount']),
                'type' => 0,
                'key' => '',
                'is_selected' => 0,
            ];
        }
        $resData = [
            'progress_data' => $progressData,
            'status' => $orderInfo['status'],
            'img' => $goodAttrData['img'],
            'title' => $goodData['name'],
            'spe_name' => $goodAttrData['name'],
            'sid' => $orderInfo['qid'],
            'gid' => $extend['mall']['gid'],
            'detail_list' => $detailList,
            'address_data' => $addressData,
            'end_pay_time' => $orderInfo['status'] === 1 ? max($this->orderPayCloseDelayTime + $orderInfo['create_time'] - $this->request->time(), 0) : 0,
            'pay_mode_list' => $payModeList,
            'price' => $orderInfo['total_amount'],
        ];
        return show(config('code.success'), '请求成功', $resData);
    }
}
